package de.sendorian.app.forumArchive;

import static de.sendorian.app.forumArchive.renamer.Renamers.nothing;
import static org.hamcrest.Matchers.anything;

import java.text.SimpleDateFormat;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;
import org.hamcrest.Matcher;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import de.sendorian.app.forumArchive.domain.Forum;
import de.sendorian.app.forumArchive.domain.Post;
import de.sendorian.app.forumArchive.domain.Topic;
import de.sendorian.app.forumArchive.finder.Finder;
import de.sendorian.app.forumArchive.renamer.FileRenamer;
import de.sendorian.util.matcher.PropertyMatcher;


@Component
public abstract class Config {

    private static final Logger LOG = Logger.getLogger(Config.class);

    /**
     * If this matcher matches, the property was not set (otherwise it would
     * have been replaced with its value.
     */
    private static final PropertyMatcher property = new PropertyMatcher();

    protected static Config config;

    private String downloadDir;
    private String month;
    private String sEndDate;
    private String sStartDate;
    protected DateTime startDate;
    protected DateTime endDate;


    public abstract String getBaseUrl();


    public abstract SimpleDateFormat getDateFormat();


    public abstract Pattern getDatePattern();


    public FileRenamer getDefaultRenamer() {
        return nothing();
    }


    public String getDownloadDir() {
        return downloadDir;
    }


    protected DateTime getEndDate() {
        if (endDate == null) {
            if (sEndDate != null) {
                endDate = new DateTime(sEndDate);
            } else {
                try {
                    endDate = getStartDate().dayOfMonth().withMaximumValue();
                } catch (Exception e) {
                    LOG.error("Could not parse end_date property or " + "property does not exist.", e);
                }
            }
            LOG.info("Configured end date: " + endDate);
        }
        return endDate;
    }


    public abstract Finder<String, Forum> getForumFinder();


    protected String getMonth() {
        return month;
    }


    public abstract Finder<Topic, Post> getPostFinder();


    public Matcher<Post> getPostMatcher() {
        return anything();
    }


    protected DateTime getStartDate() {
        if (startDate == null) {
            if (sStartDate != null) {
                startDate = new DateTime(sStartDate);
            } else {
                try {
                    String propertyMonth = getMonth();
                    if (propertyMonth == null) {
                        LOG.info("Properties 'month' and 'start_date' not set. " + "Using actual month as default.");
                        startDate = new DateTime().dayOfMonth().withMinimumValue();
                    } else {
                        startDate = new DateTime(propertyMonth + "-01");
                    }
                } catch (Exception e) {
                    LOG.error("Could not parse start.date property or property does not exist.", e);
                }
            }
            LOG.info("Configured start date: " + startDate);
        }
        return startDate;
    }


    public abstract Finder<Forum, Topic> getTopicFinder();


    public Matcher<Topic> getTopicMatcher() {
        return anything();
    }


    @Value("#{props['download_dir']}")
    public void setDownloadDir(String downloadDir) {
        this.downloadDir = (property.matches(downloadDir) ? "" : downloadDir);
    }


    @Value("#{props['end_date']}")
    public void setEndDate(String endDate) {
        this.sEndDate = (property.matches(endDate) ? null : endDate);
    }


    @Value("#{props['month']}")
    public void setMonth(String month) {
        this.month = (property.matches(month) ? null : month);
    }


    @Value("#{props['start_date']}")
    public void setStartDate(String startDate) {
        this.sStartDate = (property.matches(startDate) ? null : startDate);
    }

}
